package com.arc.spring.proxy.dynamic.cglib;

import org.springframework.cglib.proxy.Enhancer;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;

import java.lang.reflect.Method;

/**
 * @author YangYunhe
 * @date 2025/1/1
 * @description cglib 代理模式
 * 1、面向父类的，和接口没有直接的关系
 * 2、不仅可以增强父类中定义的方法，还可以增强类中的其他方法
 * 3、可以读取父类方法中的所有注解
 */
public class CglibProxyDemo {

    public static void main(String[] args) {

        // 1、获得 Enhancer 对象
        Enhancer enhancer = new Enhancer();
        // 2、设置父类的类对象
        enhancer.setSuperclass(Person.class);
        // 3、获取 MethodInterceptor 对象，用于定义增强规则
        MethodInterceptor methodInterceptor = new MethodInterceptor() {
            /**
             *
             * @param o 生成之后的代理对象，下文的 personProxy
             * @param method 父类中要执行的方法，本案例中的 eat() 方法
             * @param objects 方法在调用时传入的实参数组
             * @param methodProxy 子类中重写父类的方法 personProxy 的 eat() 方法
             * @return 方法的返回值
             */
            @Override
            public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
                Object res = null;
                // 如果是 eat() 方法则增强并运行
                if ("eat".equals(method.getName())) {
                    System.out.println("饭前洗手");
                    res = methodProxy.invokeSuper(o, objects);
                    System.out.println("饭后洗碗");
                } else { // 其他方法只运行不增强
                    // 子类对象方法执行，默认调用父类中被重写的方法
                    res = methodProxy.invokeSuper(o, objects);
                }

                return res;
            }
        };
        // 4、设置 MethodInterceptor
        enhancer.setCallback(methodInterceptor);
        // 5、获得代理对象
        Person personProxy = (Person) enhancer.create();
        // 6、使用代理对象完成功能
        personProxy.eat("apples");

    }

}

class Person {

    public Person() {

    }

    public void eat(String foodName) {
        System.out.println("person eats " + foodName);
    }

}